package compile;

import java.util.LinkedList;
import java.util.List;

/**
 * @author SongJun
 * @description TODO:
 * @date 2021/9/28 15:41
 */
public class Parser {
    private Tokenizer tokenizer;

    public Parser(Tokenizer tokenizer) {
        this.tokenizer = tokenizer;
    }

    public Prog parseProg(){
        List<Statement> stmts = new LinkedList<>();
        Statement stmt = null;
        while(true){
            //尝试一下函数声明
            stmt = this.parseFunctionDecl();
            if (Statement.isStatementNode(stmt)){
                stmts.add(stmt);
                continue;
            }

            //如果前一个尝试不成功，那么再尝试一下函数调用
            stmt = this.parseFunctionCall();
            if (Statement.isStatementNode(stmt)){
                stmts.add(stmt);
                continue;
            }

            //如果都没成功，那就结束
            if (stmt == null){
                break;
            }
        }
        return new Prog(stmts);
    }

    private FunctionDecl parseFunctionDecl(){
        System.out.println("in FunctionDecl");
        Token t = this.tokenizer.next();
        if(t.kind.equals(TokenKindEnum.Keyword) && t.text.equals("function")){
            t = this.tokenizer.next();
            if (t.kind.equals(TokenKindEnum.Identifier)){
                //读取"("和")"
                Token t1 = this.tokenizer.next();
                if (t1.text.equals("(")){
                    Token t2 = this.tokenizer.next();
                    if (t2.text.equals(")")){
                        FunctionBody functionBody = this.parseFunctionBody();
                        if (FunctionBody.isFunctionBodyNode(functionBody)){
                            //如果解析成功，从这里返回
                            return new FunctionDecl(t.text, functionBody);
                        } else {
                            System.out.println("Error parsing FunctionBody in FunctionDecl");
                            return null;
                        }
                    }
                    else{
                        System.out.println("Expecting ')' in FunctionDecl, while we got a " + t.text);
                    }
                }
                else{
                    System.out.println("Expecting '(' in FunctionDecl, while we got a " + t.text);
                }
            } else {
                System.out.println("Expecting a function name, while we got a " + t.text);
                return null;
            }
        }
        return null;
    }

    private FunctionBody parseFunctionBody(){
        List<FunctionCall> stmts = new LinkedList<>();
        Token t = this.tokenizer.next();
        if(t.text.equals("{")){
            while(this.tokenizer.peek().kind.equals(TokenKindEnum.Identifier)){  //解析函数体
                FunctionCall functionCall = this.parseFunctionCall();
                if(functionCall != null){
                    stmts.add(functionCall);
                } else {
                    System.out.println("Error parsing a FunctionCall in FunctionBody.");
                    return null;
                }
            }
            t = this.tokenizer.next();
            if (t.text.equals("}")){
                return new FunctionBody(stmts);
            }
            else{
                System.out.println("Expecting '}' in FunctionBody, while we got a " + t.text);
            }
        }
        else{
            System.out.println("Expecting '{' in FunctionBody, while we got a " + t.text);
        }

        return null;
    }

    private FunctionCall parseFunctionCall(){
        List<String> params = new LinkedList<>();
        Token t = this.tokenizer.next();
        if(t.kind.equals(TokenKindEnum.Identifier)){
            Token t1 = this.tokenizer.next();
            if (t1.text.equals("(")){
                Token t2 = this.tokenizer.next();
                //循环，读出所有
                while(!t2.text.equals(")")){
                    if (t2.kind.equals(TokenKindEnum.StringLiteral)){
                        params.add(t2.text);
                    } else {
                        System.out.println("Expecting parameter in FunctionCall, while we got a " + t2.text);
                        return null;  //出错时，就不在错误处回溯了。
                    }
                    t2 = this.tokenizer.next();
                    if (!t2.text.equals(")")){
                        if (t2.text.equals(",")){
                            t2 = this.tokenizer.next();
                        } else{
                            System.out.println("Expecting a comma in FunctionCall, while we got a " + t2.text);
                            return null;
                        }
                    }
                }
                //消化掉一个分号：;
                t2 = this.tokenizer.next();
                if (t2.text.equals(";")){
                    return new FunctionCall(t.text, params);
                }
                else{
                    System.out.println("Expecting a comma in FunctionCall, while we got a " + t2.text);
                    return null;
                }
            }
        }

        //如果解析不成功，回溯，返回null。
//        this.tokenizer.traceBack(oldPos);
        return null;
    }
}
